package com.sky.util;

import com.jfinal.log.Log;
import com.sky.model.entity.Message;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.net.ssl.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

/**
 * String userCode="STJ_XTY_00001001";
 * String userPass="MXHunOsi";
 *
 * @author：吴世凯 日期：2020/4/23
 * 提供出来的接口，入参包括用户名，密码，短信内容。 需要调用的时候, 用post提交，直接传这些内容就可以发送,
 * 创建一个方法, 来比对结果
 */

public class MessageUtil {
	static HashMap<String, String> errorCodeMap = new HashMap<>();
	static {
		errorCodeMap.put(   "-1"     , "应用程序错误");
		errorCodeMap.put(   "-3"     , "用户名或密码错误");
		errorCodeMap.put(   "-4"     , "短信内容和备案的模板不一样");
		errorCodeMap.put(   "-5"     , "签名不正确");
		errorCodeMap.put(   "-7"     , "余额不足");
		errorCodeMap.put(   "-8"     , "无可用通道或不在通道时间范围");
		errorCodeMap.put(   "-9"     , "无效号码");
		errorCodeMap.put(   "-10"    , "签名内容不符合长度");
		errorCodeMap.put(   "-11"    , "用户有效期过期");
		errorCodeMap.put(   "-12"    , "黑名单");
		errorCodeMap.put(   "-16"    , "接口请求过于频繁，余额接口 5s 秒一次，其他接口适当调整");
		errorCodeMap.put(   "-17"    , "非法 IP");
		errorCodeMap.put(   "-18"    , "Msg 内容格式错误");
		errorCodeMap.put(   "-19"    , "短信数量错误,小于 1 /大于 500(个性化)/大于 1000（群发）");
		errorCodeMap.put(   "-20"    , "号码错误或者黑名单");
		errorCodeMap.put(   "-23"    , "解密失败");
		errorCodeMap.put(   "-24"    , "短信包含敏感信息");
		errorCodeMap.put(   "-25"    , "用户被冻结");
		errorCodeMap.put(   "-26"    , "无效数据");
		errorCodeMap.put(   "-27"    , "请求参数错误");
		errorCodeMap.put(   "-28"    , "无效数据");
		errorCodeMap.put(   "-41"    , "指定短信模板类型错误或短信类型参数错误");
		errorCodeMap.put(   "-44"    , "自定义扩展号不符合规则（1-9 位数字）");
		errorCodeMap.put(   "-46"    , "用户黑名单");
		errorCodeMap.put(   "-47"    , "系统黑名单");
		errorCodeMap.put(   "-48"    , "号码超频拦截");
		errorCodeMap.put(   "-51"    , "超过设置的每月短信条数的限制");

	}

	static Log logger = Log.getLog(MessageUtil.class);

	/**
	 * 此方法只发送一条短信
	 *
	 * @param userCode 登录名称 必填
	 * @param userPass 登录密码 必填
	 * @param DesNo    手机号码 必填 (每次只能提交 1 个号码)
	 * @param Msg      短信内容 必填 Msg格式参考:1234【通联支付】, 【】里面的签名必须有, 但是随你写, 没有签名就报错
	 * @return autograph string 签名编号，非必填， 留空
	 * customerUuid string 用户标识字段，非必填（最大长度 32 位）
	 * 发送成功：可以得到本次提交的批次号, 比如2004231745612875963 失败:返回错误码, 比如:-7 , -5
	 */
	public static Message sendAMsg(String userCode, String userPass, String DesNo, String Msg) {
		String url = "https://118.178.116.15:8443/winnerrxd/api/trigger/SendMsg";
		/*Msg格式 签名必须有, 没有签名就报错, 但是内容随你写, 只不过没有头像, 能写中文 */
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("userCode", userCode);
		paramMap.put("userPass", userPass);
		paramMap.put("DesNo", DesNo);
		paramMap.put("autograph", "");
		paramMap.put("Msg", Msg);
		paramMap.put("customerUuid", "");
		//paramMap.put("smsType",smsType.toString());
		Message message = new Message();
		try {

			String postResult = httpsPost(url, paramMap);	//POST请求, 有可能出异常
			String code = getXmlParseResult(postResult);
			if (code==null){return null;}
			if (errorCodeMap.containsKey(code)){
				message.setCode(code);
				message.setMsg(errorCodeMap.get(code));
				return message;
			}else {
				//0000 表示发送成功
				message.setCode("0000");
				//返回的信息就是批次号
				message.setMsg(code);
				return message;
			}
		} catch (Exception e) {
			logger.error("调用https失败, 发送单条短信时出现异常:" + e.getMessage());
			return null;//出异常, 返回空
		}
	}


	/**
	 * 此方法批量发送相同内容短信
	 *
	 * @param userCode 登录名称 必填
	 * @param userPass 登录密码  必填
	 * @param DesNos   多个手机号码的String数组 必填
	 * @param Msg      短信内容 必填 Msg格式参考:1234【通联支付】, 【】里面的签名必须有, 但是随你写, 没有签名就报错
	 * @return autograph string 签名编号，非必填，留空
	 * smsType Integer 短信类型（101 触发类），非必填，可为空
	 * 发送成功：可以得到本次提交的批次号, 比如2004231745612875963 失败:返回错误码, 比如:-7 , -5
	 */
	public static Message sendMultiMessage(String userCode, String userPass, String DesNos[], String Msg) {
		String url = "https://118.178.116.15:8443/winnerrxd/api/trigger/SendBatchMsg";
		String DesNo = "";
		for (int i = 0; i < DesNos.length; i++) {
			if (i == 0) {

				DesNo += DesNos[i];
			} else {
				DesNo += "," + DesNos[i];
			}

		}
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("userCode", userCode);
		paramMap.put("userPass", userPass);
		paramMap.put("DesNo", DesNo);
		paramMap.put("autograph", "");
		paramMap.put("Msg", Msg);
		paramMap.put("customerUuid", "");
		Message message=new Message();
		try {
			String postResult = httpsPost(url, paramMap); //POST请求, 可能出异常
			String code = getXmlParseResult(postResult);
			if (code==null){return null;}
			if ( errorCodeMap.containsKey(code)){
				message.setCode(code);
				message.setMsg(errorCodeMap.get(code));
				return message;
			}else {
				//0000 表示发送成功
				message.setCode("0000");
				//返回的信息就是批次号
				message.setMsg(code);
				return message;
			}
		} catch (Exception e) {
			logger.error("调用https失败, 群发短信时出现异常:" + e.getMessage());
		}
		return null;
	}


	/**
	 * 短信发送成功之后, 系统发送回来的xml字符串
	 * <?xml version="1.0" encoding="utf-8"?><string  xmlns="http://tempuri.org/">2004241445800413936</string>
	 * 解析返回来的xml字符串中的<string> 节点内容
	 *
	 * @param strXML
	 * @return
	 */
	public static String getXmlParseResult(String strXML) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		Document doc = null;
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			StringReader sr = new StringReader(strXML);
			InputSource is = new InputSource(sr);
			doc = builder.parse(is);
			doc.getDocumentElement().normalize();
			NodeList nList = doc.getElementsByTagName("string");
			//获取<String> 节点
			Node item = nList.item(0);
			//获取<String> 节点的文本
			String textContent = item.getTextContent();
			//根据返回来的字符串长度判断是否发送成功
			return textContent;
		} catch (Exception e) {
			logger.error("返回字符串解析异常: "+e.getMessage());
			return null;
		}

	}


	private static class TrustAnyTrustManager implements X509TrustManager {

		@Override
		public void checkClientTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
		}

		@Override
		public void checkServerTrusted(X509Certificate[] chain, String authType)
				throws CertificateException {
		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			return new X509Certificate[]{};
		}
	}

	private static class TrustAnyHostnameVerifier implements HostnameVerifier {
		@Override
		public boolean verify(String hostname, SSLSession session) {
			return true;
		}
	}

	public static String httpsGet(String url, Map<String, String> params) throws
			Exception {
		String result = "";
		BufferedReader in = null;
		try {

			String urlStr = url + "?" + getParamStr(params);

			System.out.println("GET请求的URL为：" + urlStr);
			SSLContext sc = SSLContext.getInstance("SSL");
			sc.init(null, new TrustManager[]{new TrustAnyTrustManager()},
					new java.security.SecureRandom());
			URL realUrl = new URL(urlStr);
			// 打开和URL之间的连接
			HttpsURLConnection connection = (HttpsURLConnection)
					realUrl.openConnection();
			//设置https相关属性
			connection.setSSLSocketFactory(sc.getSocketFactory());
			connection.setHostnameVerifier(new TrustAnyHostnameVerifier());
			connection.setDoOutput(true);

			// 设置通用的请求属性
			connection.setRequestProperty("accept", "*/*");
			connection.setRequestProperty("connection", "Keep-Alive");
			connection.setRequestProperty("user-agent",
					"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			// 建立实际的连接
			connection.connect();

			// 定义 BufferedReader输入流来读取URL的响应
			in = new BufferedReader(new
					InputStreamReader(connection.getInputStream(), "UTF-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
			System.out.println("获取的结果为：" + result);
		} catch (Exception e) {
			System.out.println("发送GET请求出现异常！" + e);
			//e.printStackTrace();
			throw e;
		}
		// 使用finally块来关闭输入流
		finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e2) {
				//e2.printStackTrace();
				throw e2;
			}
		}
		return result;

	}


	public static String httpsPost(String url, Map<String, String> params)
			throws Exception {
		String result = "";
		BufferedReader in = null;
		String content = getParamStr(params);
		try {
			System.out.println("POST请求的URL为：" + url);
			SSLContext sc = SSLContext.getInstance("SSL");
			sc.init(null, new TrustManager[]{new TrustAnyTrustManager()},
					new java.security.SecureRandom());
			//--------------------------------------------> 			URL console = new URL( url);
			// java.lang.ClassCastException: sun.net.www.protocol.http.HttpURLConnection cannot be cast to javax.net.ssl.HttpsURLConnection

			URL console = new URL(null, url, new sun.net.www.protocol.https.Handler());
			HttpsURLConnection connection = (HttpsURLConnection)
					console.openConnection();
			connection.setSSLSocketFactory(sc.getSocketFactory());
			connection.setHostnameVerifier(new TrustAnyHostnameVerifier());
			connection.setDoOutput(true);
			connection.connect();
			DataOutputStream out = new
					DataOutputStream(connection.getOutputStream());
			out.write(content.getBytes("UTF-8"));
			// 刷新、关闭
			out.flush();
			out.close();
			// 定义 BufferedReader输入流来读取URL的响应
			in = new BufferedReader(new
					InputStreamReader(connection.getInputStream(), "UTF-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
			logger.debug("获取的结果为：" + result);
		} catch (Exception e) {
			//System.out.println("发送POST请求出现异常！" + e);
			//e.printStackTrace();
			logger.info("发送POST请求出现异常！" + e.getMessage());
			throw e;
		}
		// 使用finally块来关闭输入流
		finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e2) {
				//e2.printStackTrace();
				throw e2;
			}
		}
		return result;
	}

	private static String getParamStr(Map<String, String> params) {
		String paramStr = "";
		if (params != null && params.size() > 0) {
			// 获取参数列表组成参数字符串
			for (String key : params.keySet()) {
				paramStr += key + "=" + params.get(key) + "&";
			}
			//去除最后一个"&"
			paramStr = paramStr.substring(0, paramStr.length() - 1);
		}
		return paramStr;
	}



}
